package cn.jinbyte.web.interceptor;

import cn.jinbyte.web.dao.WebLogDao;
import cn.jinbyte.web.model.LogInclude;
import cn.jinbyte.web.model.LogRecord;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.Getter;
import org.springframework.lang.NonNull;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import java.time.Instant;
import java.util.Set;

import static cn.jinbyte.web.config.WebConst.ATTR_START_LOG_TIME;

/**
 * 请求拦截日志处理接口
 *
 * @author jinty
 */
public abstract class RequestLogInterceptor implements HandlerInterceptor {


    /**
     * 全局配置可选包含信息
     */
    @Getter
    private final Set<LogInclude> includes;

    /**
     * 日志记录接口
     */
    @Getter
    private final WebLogDao logDao;

    public RequestLogInterceptor(Set<LogInclude> includes, WebLogDao logDao) {
        this.includes = includes;
        this.logDao = logDao;
    }

    /**
     * 是否拦截处理请求
     *
     * @param targetMethod 目标方法
     * @return true: 忽略
     */
    public abstract boolean isLog(HandlerMethod targetMethod);


    /**
     * 构建日志
     *
     * @param request       请求
     * @param response      响应
     * @param handlerMethod 目标方法
     * @param ex            异常
     * @param includes      包含信息
     * @return 日志记录信息
     */
    public abstract LogRecord buildLog(HttpServletRequest request, HttpServletResponse response,
                                       HandlerMethod handlerMethod, Exception ex, Set<LogInclude> includes);

    /**
     * 保存日志
     *
     * @param logRecord 日志记录信息
     */
    public void log(LogRecord logRecord) {
        logDao.add(logRecord);
    }


    @Override
    public boolean preHandle(@NonNull HttpServletRequest request, @NonNull HttpServletResponse response,
                             @NonNull Object handler) {
        if (handler instanceof HandlerMethod handlerMethod && isLog(handlerMethod)) {
            request.setAttribute(ATTR_START_LOG_TIME, Instant.now());
        }
        return true;
    }

    @Override
    public void postHandle(@NonNull HttpServletRequest request, @NonNull HttpServletResponse response,
                           @NonNull Object handler, ModelAndView modelAndView) {
    }

    @Override
    public void afterCompletion(@NonNull HttpServletRequest request, @NonNull HttpServletResponse response,
                                @NonNull Object handler, Exception ex) {
        if (handler instanceof HandlerMethod handlerMethod) {
            LogRecord logRecord = buildLog(request, response, handlerMethod, ex, includes);
            if (logRecord != null) {
                log(logRecord);
            }
        }
    }
}
